use axplat::init::InitIf;

#[allow(unused_imports)]
use crate::config::devices::{
    GICC_PADDR, GICD_PADDR, TIMER_IRQ,
    GPIO0_PADDR, GPIO1_PADDR, GPIO2_PADDR, GPIO3_PADDR, GPIO4_PADDR,
};
use crate::config::plat::PSCI_METHOD;

struct InitIfImpl;

#[impl_plat_interface]
impl InitIf for InitIfImpl {
    /// Initializes the platform at the early stage for the primary core.
    ///
    /// This function should be called immediately after the kernel has booted,
    /// and performed earliest platform configuration and initialization (e.g.,
    /// early console, clocking).
    fn init_early(_cpu_id: usize, _dtb: usize) {
        axplat::console_println!("init_early on RK3588");
        axcpu::init::init_trap();
        axplat_aarch64_peripherals::psci::init(PSCI_METHOD);

        // Todo, compatible = "rockchip,rk3588-uart\0snps,dw-apb-uart"
        // The serial port can be used directly by default without the need for init
        // super::dw_apb_uart::init_early();

        axplat_aarch64_peripherals::generic_timer::init_early();
    }

    /// Initializes the platform at the early stage for secondary cores.
    #[cfg(feature = "smp")]
    fn init_early_secondary(_cpu_id: usize) {
        axcpu::init::init_trap();
    }

    /// Initializes the platform at the later stage for the primary core.
    ///
    /// This function should be called after the kernel has done part of its
    /// initialization (e.g, logging, memory management), and finalized the rest
    /// of platform configuration and initialization.
    fn init_later(_cpu_id: usize, _dtb: usize) {
        #[cfg(feature = "irq")]
        {
            use axplat::mem::pa;

            use crate::mem::phys_to_virt;
            axplat_aarch64_peripherals::gic::init_gic(
                phys_to_virt(pa!(GICD_PADDR)),
                phys_to_virt(pa!(GICC_PADDR)),
            );
            axplat_aarch64_peripherals::gic::init_gicc();
            axplat_aarch64_peripherals::generic_timer::enable_irqs(TIMER_IRQ);

            // enable UART IRQs
            // crate::dw_apb_uart_old::init_irq();
            // crate::console::init_early();
            crate::console::init_irq();
            // crate::console::init_early();
        }
        
        // Initialize GPIO controllers
        init_gpio();
    }

    /// Initializes the platform at the later stage for secondary cores.
    #[cfg(feature = "smp")]
    fn init_later_secondary(_cpu_id: usize) {
        #[cfg(feature = "irq")]
        {
            axplat_aarch64_peripherals::gic::init_gicc();
            axplat_aarch64_peripherals::generic_timer::enable_irqs(TIMER_IRQ);
        }
    }
}

/// Initialize GPIO controllers
fn init_gpio() {
    use axplat::mem::pa;
    use crate::mem::phys_to_virt;
    
    // Prepare GPIO base addresses
    let gpio_bases = [
        phys_to_virt(pa!(GPIO0_PADDR)),
        phys_to_virt(pa!(GPIO1_PADDR)),
        phys_to_virt(pa!(GPIO2_PADDR)),
        phys_to_virt(pa!(GPIO3_PADDR)),
        phys_to_virt(pa!(GPIO4_PADDR)),
    ];
    
    // Initialize all GPIO controllers
    axplat_aarch64_peripherals::rk3588_gpio::init_all(&gpio_bases);
    
    axplat::console_println!("GPIO controllers initialized");
}
